
#include "esp_log.h"
#include "nvs_flash.h"

#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "console/console.h"
#include "host/ble_uuid.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"

#include "ble_server.h"

#define TAG "BLE_SERVER"

#define BLE_DEVICE_NAME "ESP32S3-NIMBLE"

// 定义服务和特性的 UUID
static const ble_uuid128_t gatt_service_uuid = BLE_UUID128_INIT(0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
                                                                0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff);
static const ble_uuid128_t gatt_char_uuid = BLE_UUID128_INIT(0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd,
                                                             0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd);

// 特性值
static uint8_t char_value[16] = "Hello, BLE!";
static uint16_t char_val_handle; // 特性值的句柄
static uint16_t conn_handle = BLE_HS_CONN_HANDLE_NONE;
static const char *device_name = BLE_DEVICE_NAME;

// GATT 特性访问回调
static int gatt_char_access(uint16_t conn_handle, uint16_t attr_handle,
                            struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    int rc;

    switch (ctxt->op)
    {
    case BLE_GATT_ACCESS_OP_READ_CHR:
        ESP_LOGI(TAG, "Characteristic read request");
        rc = os_mbuf_append(ctxt->om, char_value, sizeof(char_value));
        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;

    case BLE_GATT_ACCESS_OP_WRITE_CHR:
        ESP_LOGI(TAG, "Characteristic write request");
        if (ctxt->om->om_len <= sizeof(char_value))
        {
            memset(char_value, 0, sizeof(char_value)); // 清空旧值
            memcpy(char_value, ctxt->om->om_data, ctxt->om->om_len);
            ESP_LOGI(TAG, "New value: %.*s", ctxt->om->om_len, char_value);
            return 0;
        }
        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;

    default:
        return BLE_ATT_ERR_UNLIKELY;
    }
}

// GATT 服务定义
static const struct ble_gatt_svc_def gatt_svcs[] = {
    {
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = &gatt_service_uuid.u,
        .characteristics = (struct ble_gatt_chr_def[]){
            {
                .uuid = &gatt_char_uuid.u,
                .access_cb = gatt_char_access,
                .val_handle = &char_val_handle, // 保存特性句柄
                .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
            },
            {0} // 结束特性定义
        },
    },
    {0} // 结束服务定义
};

// GAP 事件处理
static int gap_event(struct ble_gap_event *event, void *arg)
{
    switch (event->type)
    {
    case BLE_GAP_EVENT_CONNECT:
        ESP_LOGI(TAG, "BLE connected, handle: %d", event->connect.conn_handle);
        conn_handle = event->connect.conn_handle;
        break;

    case BLE_GAP_EVENT_DISCONNECT:
        ESP_LOGI(TAG, "BLE disconnected, reason: %d", event->disconnect.reason);
        conn_handle = BLE_HS_CONN_HANDLE_NONE;
        ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
                          NULL, gap_event, NULL);
        break;

    case BLE_GAP_EVENT_ADV_COMPLETE:
        ESP_LOGI(TAG, "Advertising stopped");
        break;

    default:
        break;
    }
    return 0;
}

// BLE 主机任务
static void ble_host_task(void *param)
{
    nimble_port_run();
    nimble_port_freertos_deinit();
}

esp_err_t ble_server_init(void)
{
    esp_err_t ret;

    // 初始化 NVS
    ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    // 初始化 Nimble
    nimble_port_init();
    ble_hs_cfg.reset_cb = NULL;          // 可选：自定义复位回调
    ble_hs_cfg.gatts_register_cb = NULL; // 可选：服务注册回调
    ble_svc_gap_init();
    ble_svc_gatt_init();

    // 设置设备名称
    ble_svc_gap_device_name_set("ESP32S3_BLE");

    // 注册 GATT 服务
    ret = ble_gatts_count_cfg(gatt_svcs);
    ESP_ERROR_CHECK(ret);
    ret = ble_gatts_add_svcs(gatt_svcs);
    ESP_ERROR_CHECK(ret);

    return ESP_OK;
}

esp_err_t ble_server_start(void)
{
    // 启动主机任务
    nimble_port_freertos_init(ble_host_task);

    struct ble_hs_adv_fields adv_fields;
    memset(&adv_fields, 0, sizeof(adv_fields));

    // 设置广播类型
    adv_fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;

    // 设备名称
    adv_fields.name = (uint8_t *)device_name;
    adv_fields.name_len = strlen(device_name);
    adv_fields.name_is_complete = 1;

    // 设置广播数据
    esp_err_t rc = ble_gap_adv_set_fields(&adv_fields);
    if (rc != 0)
    {
        ESP_LOGE(TAG, "Setting advertisement data failed: %d", rc);
        return ESP_FAIL;
    }

    // 启动广播
    struct ble_gap_adv_params adv_params = {
        .conn_mode = BLE_GAP_CONN_MODE_UND, // 无定向连接
        .disc_mode = BLE_GAP_DISC_MODE_GEN, // 通用可发现模式
        .itvl_max = 64,
        .itvl_min = 64,
    };
    ESP_ERROR_CHECK(ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
                                      &adv_params, gap_event, NULL));

    ESP_LOGI(TAG, "BLE advertising started");
    return ESP_OK;
}

esp_err_t ble_server_stop(void)
{
    if (conn_handle != BLE_HS_CONN_HANDLE_NONE)
    {
        ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
    }
    ESP_ERROR_CHECK(ble_gap_adv_stop());
    nimble_port_stop();
    ESP_LOGI(TAG, "BLE server stopped");
    return ESP_OK;
}
